package storage.v1;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;

import org.apache.commons.lang.StringEscapeUtils;

import storage.v1.PictureDataStorage.PictureCollection;
import storage.v1.PictureDataStorage.PictureData;

import com.onpositive.commons.platform.registry.IAdaptable2;
import com.onpositive.data.IPropertyConstants;
import com.onpositive.mediawiki.propertyparser.ParsedCategory;
import com.onpositive.mediawiki.propertyparser.ParsedDocument;
import com.onpositive.mediawiki.propertyparser.TextParagraphParser;
import com.onpositive.semantic.model.api.property.IProperty;
import com.onpositive.semantic.model.api.property.IPropertyProvider;
import com.onpositive.units.ParsedFileList;
import com.onpositive.units.ParsedProperty;
import com.onpositive.units.ParsedValue;
import com.onpositive.wikistorage.PictureManager;
import com.onpositive.wikitemplate.DefaultTemplateResolver;

public class PictureInfoExtractor extends AbstractValueExtractor {

	public static final String WIKIPEDIA_FILE_PATH = "http://en.wikipedia.org/wiki/File:" ;
	
	private static String pictureExtensions = "(jpg|jpeg|JPG|JPEG|Jpeg|Jpg|png|PNG|gif|GIF|tif|TIF|tiff|TIFF)" ;
	public static String[] picKeys = {"File", "file", "Image", "image", "IMAGE"};
	
	private PictureManager pictureManager = null ;
	
	private PictureDataStorage pictureDataStorage = null ; 
	@Override
	public void process( String text, ParsedDocument pDoc, IParserProvider parserProvider, IAdaptable2 adaptable ) 
	{
		IPropertyProvider propertyProvider = adaptable.getAdapter( IPropertyProvider.class ) ;
		
		String[] splitArray = text.split("\n") ;
		ArrayList<String> documentContent = new ArrayList<String>( splitArray.length ) ;
		for( int i = 0 ; i < splitArray.length ; i++ )
			documentContent.add( splitArray[i].replace("&nbsp;", " ").trim() ) ;
		
		ArrayList<ArrayList<String>> lst = new ArrayList<ArrayList<String>>() ;
		extractPictureNamesAndcomments(propertyProvider, documentContent, lst);
		
		if( !extractWWWLinks(pDoc, adaptable, lst) )
			return ;
		
		//testCommentOutput(pDoc, lst);
		contributePropertyValues(pDoc, lst);
	}

	

	private boolean extractWWWLinks(ParsedDocument pDoc, IAdaptable2 adaptable,
			ArrayList<ArrayList<String>> lst) {
		
		ArrayList<String> pictures = lst.get(0) ;
		ArrayList<String> comments = lst.get(1) ;
		lst.add( new ArrayList<String>() ) ;
		ArrayList<String> wwwLinks = lst.get(2) ;
		
		if( pictures.size() == 0)
			return false;
		
		if( pictureDataStorage == null ){
			ParsedCategory category = pDoc.getCategory();
			if( category == null )
				category = adaptable.getAdapter( ParsedCategory.class ) ;
			pictureDataStorage = new PictureDataStorage( category.getRootPath() ) ;
		}
		
		String docName = pDoc.getName();
		PictureDataStorage.PictureCollection oldPictureCollection = pictureDataStorage.getPictureData( docName ) ;		
		if( oldPictureCollection == null )
			oldPictureCollection = new PictureCollection(docName) ;
		
		PictureDataStorage.PictureCollection newPictureCollection = new PictureCollection( docName ) ;
		pictureDataStorage.putPictureData(newPictureCollection) ;
		
		
		ArrayList<String> wwwLinks_old = null ;
		//wwwLinks_old = extractExistingListOfWWWLinks(pDoc);		
		
					
		int size = pictures.size();
		for( int i = 0 ; i < size ; i++ )
		{
			String picName = pictures.get(i) ;
			String comment = comments.get(i) ;
			PictureData pd = oldPictureCollection.getPictureData(picName) ;
			if( pd != null )
			{
				wwwLinks.add( pd.getWwwPath() ) ;
				newPictureCollection.addPicture(picName, "", pd.getWwwPath(), comment ) ;
				continue ;
			}
			
			String wwwLink = "err" ;
			try {
				String str = findWWWLink( picName, wwwLinks_old );
				if( str != null )
					wwwLink = str ;
				else if( picName.startsWith("http:") )
					wwwLink = picName ;
				else{
					if( pictureManager == null ){
						String categoryRootPath = pDoc.getCategory().getRootPath();
						pictureManager = PictureManager.getInstance( categoryRootPath ) ;
					}
					wwwLink = pictureManager.constructURL(picName) ;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}				
			wwwLinks.add(wwwLink) ;
			newPictureCollection.addPicture(picName, "", wwwLink, comment ) ;
		}		
		return true ;
	}
	

	private void extractPictureNamesAndcomments(
			IPropertyProvider propertyProvider,
			ArrayList<String> documentContent, ArrayList<ArrayList<String>> lst) {
		lst.add( new ArrayList<String>() ) ;
		lst.add( new ArrayList<String>() ) ;
		ArrayList<String> pictures = lst.get(0) ;
		ArrayList<String> comments = lst.get(1) ;
		
		int documentContentSize = documentContent.size() ;
		for( int i = 0 ; i < documentContentSize ; i++ )
		{
			String line = documentContent.get(i) ;
			if ( line == null || line.length() == 0 )
				continue;
			
			String[] picNameAndComment = null ;
			String comment = null ;
			String picName = null ;
			boolean gotAChange= true ;
			
			if( i+1 < documentContentSize )
			{
				String nextLine = documentContent.get(i+1) ;
				if( nextLine.replace(" ", "").startsWith( "|caption" ) )
				{
					nextLine = ParserV2.killComments(nextLine).trim() ;
					nextLine = TextParagraphParser.parse(nextLine) ;
					int ind = nextLine.indexOf("=") ;
					if( ind > 0 ){
						i++ ;
						if( ind < nextLine.length()-1 ){						
							nextLine = nextLine.replaceAll("(\\s*)(|)(\\s*)(caption)(.*)", "$2$4$5" ) ;
							int k_ = nextLine.indexOf("=") ;
							if( k_ > 0 )
								comment = nextLine.substring(k_+1).trim() ;
						}					
					}
				}
			}
			String line0 = ParserV2.killRefs( line ) ;
			while( gotAChange ){
				gotAChange = false ;
				picNameAndComment = extractNameAndComment(propertyProvider, line, line0, null );
				if( picNameAndComment != null )
				{
					gotAChange = true ;
					picName = picNameAndComment[0] ;
					line = picName ;
					line0 = picName ;
					if( comment == null )
						comment = picNameAndComment[1].trim() ;
				}
			}
			if( picName != null ){
				pictures.add( picName ) ;
				comments.add( comment ) ;
			}
		}
	}

	private ArrayList<String> extractExistingListOfWWWLinks(ParsedDocument pDoc) {
		ArrayList<String> wwwLinks_old = null ;
		ParsedProperty parsedProperty0 = pDoc.getProperty( IPropertyConstants.WWW_PICTURE_LINKS_PROPERTY_NAME );
		if( parsedProperty0 != null )
		{
			HashSet<ParsedValue> valSet = parsedProperty0.getValues() ;
			if( valSet != null && valSet.size() != 0 )
			{
				ParsedValue pVal = valSet.iterator().next() ;
				if( pVal instanceof ParsedFileList )
				{
					Object vObj = pVal.value() ;
					if( vObj instanceof ArrayList<?> )
					{
						try{
							wwwLinks_old = (ArrayList<String>) vObj ;						
						}catch(Exception e){
							
						}
					}
				}
			}
		}
		return wwwLinks_old;
	}

	public String[] extractNameAndComment(IPropertyProvider propertyProvider,
			String line, String line0, String[] picNameAndComment) {
		for( String keyWord : picKeys ){
			
			String testLine0 = line0.replaceAll("([^a-zA-Z]|\\A)(" + keyWord +")([^a-zA-z])", "" ) ;
			String testLine1 = line0.replaceAll( pictureExtensions , "" ) ;
			//if( line.indexOf( keyWord )!= -1 )
			if( testLine0.length() < line0.length() && testLine1.length() < line0.length() )
			{					
				//gotAKey = true ;
				if( line.indexOf( keyWord ) == -1 )
					continue ;
				
				if( line.length() < keyWord.length() + 5 )
					continue ;
				
				String picName1 = line0.replaceAll("(.*)([^a-zA-Z]|\\A)(" + keyWord + ":)([^\\|]*)([\\.])" + pictureExtensions + "(.*)", "$4$5$6") ;
				picName1 = picName1.trim() ;
				if( picName1.length() < line.length() && !picName1.contains(keyWord+":") ){
					picNameAndComment = new String[2] ;
					picNameAndComment[0] = picName1 ;
					picNameAndComment[1] = extractComment0( picName1, line0, propertyProvider ) ;						
					break;
				}					
				else {
					picName1 = line0.replaceAll("(.*)([^a-zA-Z]|\\A)(" + keyWord + ")([^\\|]{0,5})(=)([^\\|]*)([\\.])" + pictureExtensions + "(.*)", "$6$7$8") ;
					if( picName1.length() < line.length())
					{
						if( line.startsWith("|") ){
							picNameAndComment = new String[2] ;
							picNameAndComment[0] =picName1.replaceAll("(\\[|\\])", "").trim() ;
							picNameAndComment[1] = extractComment1( picName1, line0, propertyProvider ) ;
							break ;
						}
					}
				}					
			}
		}
		return picNameAndComment;
	}
	
	private static String extractComment0(String picName, String line, IPropertyProvider propertyProvider )
	{
		int length = line.length();
		
		int i0 = line.indexOf( picName ) ;
		int i1 = i0 + picName.length() ;
		int i2 = i1 ;
		
		int count = 1 ;
		while( i2 < length )
		{
			if( line.startsWith("]]",i2) )
			{
				if( count == 1 )
					break ;
				count-- ;				
				i2 += 2 ;
				continue ;
			}
			if( line.startsWith("[[",i2) )
			{
				count++ ;
				i2 += 2 ;
				continue ;
			}
			i2++ ;
		}
		String line0 = line.substring(i1,i2) ;
		String line1 = ParserV2.killWikiRefsLeaveCaptions(line0) ;
		line0 = line1 ;
		line1 = ParserV2.killTemplates(line0,null) ;
		line0 = line1 ;
		line1 = DefaultTemplateResolver.resolveTemplates(line0) ;
		line0 = line1;
		line1 = ParserV2.killWikiRefsLeaveCaptions( line0 ).trim();
		
		count = 0 ;
		ArrayList<Integer> arr = new ArrayList<Integer>() ;
		for( int i = line1.length()-1 ; i >= 0 ; i-- )
		{
			char ch = line1.charAt(i);
			if( ch == '|' && count == 0 )
				arr.add(i) ;
			
			else if( ch == '}' )
				count++ ;
			
			else if( ch == '{' )
				count-- ;
		}

		String result = refine( line1, arr, propertyProvider ) ;
		result = killUselessHtml(result) ;
		return result ;
	}

	private static String refine( String _str, ArrayList<Integer> arr, IPropertyProvider propertyProvider) {
		
		if( _str.length() == 0 )
			return _str ;
		int k0 = arr.size() != 0 ? arr.get(0) : 0 ;
		String str = _str.substring(k0+1).trim() ;
		
		if( str.equals("left") || str.equals("right") || str.endsWith("px") || str.equals("thumb") )
			return "" ;
		
		int ind = str.indexOf("=") ;
		if( ind < 0 )
			return str ;
		
		String pName = str.substring(0, ind).trim() ;
		IProperty prop = propertyProvider.getProperty(null, pName) ;
		
		if( pName.equals("alt") && arr.size() > 1 )
		{
			int k1 = arr.get(1)+1 ;
			str = _str.substring(k1,k0).trim() ;
			if( str.startsWith("caption") )
			{
				int k_ = str.indexOf("=") ;
				if( k_ > 0 )
					str = str.substring(k_).trim() ;
			}
			return str ;
		}
		else if( prop == null || pName.equals("caption") ){
			return str.substring(ind+1) ;
		}		
		
		int length = str.length();
		int i = ind+1 ;
		for( ; i < length && Character.isJavaIdentifierPart( str.charAt(i)) ; i++ ) ;
		
		String result = str.substring(i+1);
		return result ;
	}

	private static String extractComment1(String picName, String line, IPropertyProvider propertyProvider ) {

		int length = line.length();
		
		int i0 = line.indexOf( picName ) ;
		int i1 = i0 + picName.length() ;
		int i2 = i1 ;
		
		int count = 1 ;
		while( i2 < length )
		{
			if( line.startsWith("]",i2) )
			{
				if( count == 1 )
					break ;
				count-- ;				
			}
			else if( line.startsWith("[",i2) )
				count++ ;
			
			i2++ ;
		}
			
		String result = ParserV2.killWikiRefsLeaveCaptions( line.substring(i1,i2).trim() );
		result = killUselessHtml(result) ;
		return result ;
	}

	private static String killUselessHtml(String str) {
		
		String s= StringEscapeUtils.escapeHtml(str) ;
		s = s.replace("&lrm;", "") ;
		s = s.replace("&rlm;", "") ;
		s= StringEscapeUtils.unescapeHtml(s) ;
		return s;
	}

	private String findWWWLink(String str, ArrayList<String> wwwLinks_old)
	{
		if( wwwLinks_old == null)
			return null;
		
		String _str = str.replace(" ", "_") ;
		_str = PictureManager.performUrlEncoding( _str ) ;
		for( String s : wwwLinks_old  ){
			if( s!= null && s.endsWith(_str) )
				return s ;
		}
		
		return null;
	}
	
	private void testCommentOutput(ParsedDocument pDoc,
			ArrayList<ArrayList<String>> lst) {
		ArrayList<String> pictures = lst.get(0) ;
		ArrayList<String> comments = lst.get(1) ;
		String docName = pDoc.getName();
		
		if( comments.size() > 0 )
		{
			System.out.print("comments: ") ;
			System.out.print(docName) ;
			System.out.print("\n") ;
			for(String str : comments )
			{
				str = str.trim() ;
				System.out.print(str) ;				
				System.out.print("\n") ;
			}
			System.out.print("\n") ;
		}
	}
	
	private void contributePropertyValues(ParsedDocument pDoc,	ArrayList<ArrayList<String>> lst)
	{
		ArrayList<String> pictures = lst.get(0) ;
		ArrayList<String> comments = lst.get(1) ;
		ArrayList<String> wwwLinks = lst.get(2) ;
		
		ParsedProperty parsedProperty = pDoc.getPropertyForContribution( IPropertyConstants.PICTURE_LIST_PROPERTY_NAME );
		parsedProperty.getValues().clear() ;
		parsedProperty.addValue( new ParsedFileList( pictures, getDefaultComment() ));
		
		ParsedProperty parsedProperty0 = pDoc.getPropertyForContribution( IPropertyConstants.WWW_PICTURE_LINKS_PROPERTY_NAME );
		parsedProperty0.getValues().clear() ;
		parsedProperty0.addValue( new ParsedFileList( wwwLinks, getDefaultComment() ));
		
		ParsedProperty parsedProperty1 = pDoc.getPropertyForContribution( IPropertyConstants.WWW_PICTURE_COMMENTS );
		parsedProperty1.getValues().clear() ;
		parsedProperty1.addValue( new ParsedFileList( comments, getDefaultComment() ));
	}

	@Override
	public void dispose() {
		if( pictureManager != null ){
			pictureManager.dispose() ;
			pictureManager = null ;
		}
		if( pictureDataStorage != null )
			pictureDataStorage.saveData() ;
		pictureDataStorage = null ;
	}
}
